#include "triangle.h"

#include <SDL/SDL.h>

int DotProduct(Vector a, Vector b){
	return a.x * b.x + a.y * b.y;
}

Vector DeltaVector(Vector a, Vector b){
	Vector delta;
	delta.x = b.x - a.x;
	delta.y = b.y - a.y;
	return delta;
}

Vector PointDeltaVector(Point a, Point b){
	Vector delta;
	delta.x = b.x - a.x;
	delta.y = b.y - a.y;
	return delta;
}

int IsPointInTriangle(Point p, Triangle t){
	Vector v0 = PointDeltaVector(t.points[0], t.points[2]);
	Vector v1 = PointDeltaVector(t.points[0], t.points[1]);
	Vector v2 = PointDeltaVector(t.points[0], p);
	
	int dot00 = DotProduct(v0, v0);
	int dot01 = DotProduct(v0, v1);
	int dot02 = DotProduct(v0, v2);
	int dot11 = DotProduct(v1, v1);
	int dot12 = DotProduct(v1, v2);
	
	//double invDenom = 1.0/(dot00 * dot11 - dot01 * dot01);
	long long u = (dot11 * dot02 - dot01 * dot12);
	long long v = (dot00 * dot12 - dot01 * dot02);

	return (u >= 0) && (v >= 0) && (u + v <= (dot00 * dot11 - dot01 * dot01));

}

int ComputeScreenOffset(SDL_Surface screen, int x, int y){
	return (screen.pitch * y) + x * (screen.pitch / screen.w);
}


void DrawTriangle(SDL_Surface* screen, Triangle t){
	
	int xMin = GetMinX(t);
	int yMin = GetMinY(t);
	int xMax = GetMaxX(t);
	int yMax = GetMaxY(t);
	
	int lower = ComputeScreenOffset(*screen, xMin, yMin);
	int upper = ComputeScreenOffset(*screen, xMax, yMax);
	
	int i = lower;
	
	float oneMinusAlpha = 1.0 - t.cl.a;
	
	uint_fast8_t* pixelPointer = screen->pixels;
	
	int x,y;
	for (y = yMin; y < yMax; y++){
		for (x = xMin; x < xMax; x++){
			Point p;
			p.x = x;
			p.y = y;
			if (IsPointInTriangle(p, t)){
				int pixelPointerOffset = ComputeScreenOffset(*screen, x, y);
				pixelPointer[pixelPointerOffset] = (uint_fast8_t)(oneMinusAlpha * pixelPointer[pixelPointerOffset] + t.cl.r * t.cl.a);
				pixelPointerOffset++;
				pixelPointer[pixelPointerOffset] = (uint_fast8_t)(oneMinusAlpha * pixelPointer[pixelPointerOffset] + t.cl.g * t.cl.a);
				pixelPointerOffset++;
				pixelPointer[pixelPointerOffset] = (uint_fast8_t)(oneMinusAlpha * pixelPointer[pixelPointerOffset] + t.cl.b * t.cl.a);
			}
		}
	}
	
}

int GetMinX(Triangle t){
	int i;
	int min = LARGE;
	for (i = 0; i < 3; i++){
		if (t.points[i].x < min){
			min = t.points[i].x;
		}
	}
	
	return min;
}

int GetMinY(Triangle t){
	int i;
	int min = LARGE;
	for (i = 0; i < 3; i++){
		if (t.points[i].y < min){
			min = t.points[i].y;
		}
	}
	return min;
}

int GetMaxX(Triangle t){
	int i;
	int max = -LARGE;
	for (i = 0; i < 3; i++){
		if (t.points[i].x > max){
			max = t.points[i].x;
		}
	}
	return max;
}

int GetMaxY(Triangle t){
	int i;
	int max = -LARGE;
	for (i = 0; i < 3; i++){
		if (t.points[i].y > max){
			max = t.points[i].y;
		}
	}
	return max;
}
